unit Rule_MA;

interface

uses
  BaseRule,
  BaseRuleData;

type
  TRule_MA_I = class(TBaseRuleI64_ParamN)    
  protected           
    fInt64Ret: PArrayInt64;
    function GetMAValueI(AIndex: integer): Int64;
    procedure ComputeInt64;
  public
    constructor Create; override;
    procedure Execute; override;
    procedure Clear; override;
    property ValueI[AIndex: integer]: int64 read GetMAValueI;
    property ParamN: Word read GetParamN write SetParamN;
  end;
  
  TRule_MA_F = class(TBaseRuleF_ParamN)
  protected      
    fFloatRet: PArrayDouble;
    function GetMAValueF(AIndex: integer): double;
    procedure ComputeFloat;
  public
    constructor Create; override;
    procedure Execute; override;
    procedure Clear; override;
    property ValueF[AIndex: integer]: double read GetMAValueF;
  end;

  TPrice_Data_MA = record
    Value_MA: PChainArray;
  end;

  TRule_MA_Price = class(TBaseRuleF_ParamN)
  protected
    fPriceData_MA: TPrice_Data_MA;
    function GetValue_MA(AIndex: integer): double;
    procedure ComputeFloat;
  public
    constructor Create; override;
    procedure Execute; override;
    procedure Clear; override;
    property ValueF[AIndex: integer]: double read GetValue_MA;
    property ParamN: Word read GetParamN write SetParamN;
  end;
  
implementation

{ TRule_MA }

constructor TRule_MA_I.Create;
begin
  inherited;
  fParamN := 20;
  fInt64Ret := nil;
end;
         
constructor TRule_MA_F.Create;
begin
  inherited;
  fParamN := 20;
  fFloatRet := nil;
end;
        
procedure TRule_MA_I.Execute;
begin
  Clear;
  if Assigned(OnGetDataLength) then
  begin
    fBaseRuleData.DataLength := OnGetDataLength;
    if fBaseRuleData.DataLength > 0 then
      ComputeInt64;
  end;
end;

procedure TRule_MA_F.Execute;
begin
  Clear;
  if Assigned(OnGetDataLength) then
  begin
    fBaseRuleData.DataLength := OnGetDataLength;
    if fBaseRuleData.DataLength > 0 then
      ComputeFloat;
  end;
end;

procedure TRule_MA_I.Clear;
begin
  CheckInArrayInt64(fInt64Ret);
  fBaseRuleData.DataLength := 0;
end;
               
procedure TRule_MA_F.Clear;
begin
  CheckInArrayDouble(fFloatRet);
  fBaseRuleData.DataLength := 0;
end;

procedure TRule_MA_I.ComputeInt64;
var
  tmpInt64_Meta: PArrayInt64; 
  i: integer;
  tmpCounter: integer;
  tmpValue: Int64;
begin
  if Assigned(OnGetDataI) then
  begin
    if fInt64Ret = nil then
      fInt64Ret := CheckOutArrayInt64;
    tmpInt64_Meta := CheckOutArrayInt64;
    try
      SetArrayInt64Length(fInt64Ret, fBaseRuleData.DataLength);
      SetArrayInt64Length(tmpInt64_Meta, fBaseRuleData.DataLength);
      for i := 0 to fBaseRuleData.DataLength - 1 do
      begin
        tmpInt64_Meta.value[i] := OnGetDataI(i);
        tmpValue := tmpInt64_Meta.value[i];
        tmpCounter := fParamN - 1;
        while tmpCounter > 0 do
        begin
          if i > tmpCounter - 1 then
          begin
            tmpValue := tmpValue + tmpInt64_Meta.value[i - tmpCounter];
          end;
          Dec(tmpCounter);
        end;
        if 1 < fParamN then
        begin
          if i > fParamN - 1 then
          begin
            tmpValue := tmpValue div fParamN;
          end else
          begin
            tmpValue := tmpValue div (i + 1);
          end;
        end;
        SetArrayInt64Value(fInt64Ret, i, tmpValue);
      end;
    finally
      CheckInArrayInt64(tmpInt64_Meta);
    end;
  end;
end;

procedure TRule_MA_F.ComputeFloat;
var
  tmpFloat_Meta: PArrayDouble;  
  i: integer;
  tmpCounter: integer;
  tmpDouble: Double;
begin
  if Assigned(OnGetDataF) then
  begin                  
    if fFloatRet = nil then
      fFloatRet := CheckOutArrayDouble;
    tmpFloat_Meta := CheckOutArrayDouble;
    try
      SetArrayDoubleLength(fFloatRet, fBaseRuleData.DataLength);   
      SetArrayDoubleLength(tmpFloat_Meta, fBaseRuleData.DataLength);
      for i := 0 to fBaseRuleData.DataLength - 1 do
      begin
        tmpFloat_Meta.Value[i] := OnGetDataF(i);
        tmpDouble := tmpFloat_Meta.Value[i];
        tmpCounter := fParamN - 1;
        while tmpCounter > 0 do
        begin
          if i > tmpCounter - 1 then
          begin
            tmpDouble := tmpDouble + tmpFloat_Meta.Value[i - tmpCounter];
          end;
          Dec(tmpCounter);
        end;       
        if fParamN > 1 then
        begin      
          if i > fParamN - 1 then
          begin
            tmpDouble := tmpDouble / fParamN;
          end else
          begin
            tmpDouble := tmpDouble / (i + 1);
          end;
        end;
        SetArrayDoubleValue(fFloatRet, i, tmpDouble);
      end;
    finally
      CheckInArrayDouble(tmpFloat_Meta);
    end;
  end;
end;

function TRule_MA_I.GetMAValueI(AIndex: integer): Int64;
begin
  Result := 0;
  if fBaseRuleData.DataType = dtInt64 then
  begin
    if fInt64Ret <> nil then
    begin
      Result := GetArrayInt64Value(fInt64Ret, AIndex);
    end;
  end;
end;

function TRule_MA_F.GetMAValueF(AIndex: integer): double;
begin
  Result := 0;
  if fBaseRuleData.DataType = dtDouble then
  begin                   
    if fFloatRet <> nil then
    begin
      Result := GetArrayDoubleValue(fFloatRet, AIndex);
    end;
  end;
end;

{ TRule_MA_Price }
                 
constructor TRule_MA_Price.Create;
begin
  inherited;
  FillChar(fPriceData_MA, SizeOf(fPriceData_MA), 0);
end;

procedure TRule_MA_Price.Clear;
begin
  inherited;
  CheckInChainArray(fPriceData_MA.Value_MA);
  fBaseRuleData.DataLength := 0;
end;

procedure TRule_MA_Price.Execute;
begin
  Clear;
  if Assigned(OnGetDataLength) then
  begin
    fBaseRuleData.DataLength := OnGetDataLength;
    if fBaseRuleData.DataLength > 0 then
      ComputeFloat;
  end;
end;
         
procedure TRule_MA_Price.ComputeFloat;
begin
end;

function TRule_MA_Price.GetValue_MA(AIndex: integer): double;
begin
  Result := 0;
end;

end.
